//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//

#include <windows.h>
#include <halether.h>
#define __OAL_ETHDRV_H	// Temporary: clean up build warning until EDBG prototypes are moved.
#include <bsp.h>
#include <kitl_cfg.h>
#include "loader.h"

void LogData(BYTE btype, BYTE* pbData, DWORD dwLen);
UINT16 RndisEDbgGetFrame_stub(BYTE * pData, UINT16 *pdwLength)
{
	UINT16 ret=RndisEDbgGetFrame(pData, pdwLength);
	LogData(1, pData, *pdwLength);
 	return ret;
}

// Function pointers to the support library functions of the currently installed debug ethernet controller.
//
PFN_EDBG_INIT             pfnEDbgInit;
PFN_EDBG_ENABLE_INTS      pfnEDbgEnableInts;
PFN_EDBG_DISABLE_INTS     pfnEDbgDisableInts;
PFN_EDBG_GET_PENDING_INTS pfnEDbgGetPendingInts;
PFN_EDBG_GET_FRAME        pfnEDbgGetFrame;
PFN_EDBG_SEND_FRAME       pfnEDbgSendFrame;
PFN_EDBG_READ_EEPROM      pfnEDbgReadEEPROM;
PFN_EDBG_WRITE_EEPROM     pfnEDbgWriteEEPROM;
PFN_EDBG_SET_OPTIONS      pfnEDbgSetOptions;

/*
    @func   BOOL | InitEthDevice | Initializes the Ethernet device to be used for download.
    @rdesc  TRUE = Success, FALSE = Failure.
    @comm    
    @xref   
*/
extern BSP_ARGS *pBSPArgs;
BOOL InitEthDevice(PBOOT_CFG pBootCfg)
{
    PBYTE  pBaseIOAddress = NULL;
    UINT32 MemoryBase = 0;  
    BOOL bResult = FALSE;

    OALMSG(OAL_FUNC, (TEXT("+InitEthDevice.\r\n")));

    // Use the MAC address programmed into flash by the user.
    //
    memcpy(pBSPArgs->kitl.mac, pBootCfg->CS8900MAC, 6);

    // Use the CS8900A Ethernet controller for download.
    //
    pfnEDbgInit        = ENC28J60DBG_Init;
    pfnEDbgGetFrame    = ENC28J60DBG_GetFrame;
    pfnEDbgSendFrame   = ENC28J60DBG_SendFrame;
    pfnEDbgEnableInts  = NULL;
    pfnEDbgDisableInts = NULL;
    pfnEDbgReadEEPROM     = NULL;     
    pfnEDbgWriteEEPROM    = NULL;

    pBaseIOAddress   = (PBYTE)OALPAtoVA(pBSPArgs->kitl.devLoc.LogicalLoc, FALSE);
    MemoryBase       = (UINT32)OALPAtoVA(BSP_BASE_REG_PA_CS8900A_MEMBASE, FALSE);
    
    // Initialize the Ethernet controller.
    //
    
    if (!pfnEDbgInit((PBYTE)pBaseIOAddress, MemoryBase, pBSPArgs->kitl.mac))
    {
        OALMSG(OAL_ERROR, (TEXT("ERROR: InitEthDevice: Failed to initialize Ethernet controller.\r\n")));
        goto CleanUp;
    }
/*
    // Make sure MAC address has been programmed.
    //
    if (!pBSPArgs->kitl.mac[0] && !pBSPArgs->kitl.mac[1] && !pBSPArgs->kitl.mac[2])
    {
        OALMSG(OAL_ERROR, (TEXT("ERROR: InitEthDevice: Invalid MAC address.\r\n")));
        goto CleanUp;
    }*/

    bResult = TRUE;

CleanUp:

    OALMSG(OAL_FUNC, (TEXT("-InitEthDevice.\r\n")));
    return(bResult);
}

/*
    @func   BOOL | OEMEthGetFrame | Reads data from the Ethernet device.
    @rdesc  TRUE = Success, FALSE = Failure.
    @comm    
    @xref   
*/
BOOL OEMEthGetFrame(PUCHAR pData, PUSHORT pwLength)
{
    return(pfnEDbgGetFrame(pData, pwLength));
}


/*
    @func   BOOL | OEMEthSendFrame | Writes data to an Ethernet device.
    @rdesc  TRUE = Success, FALSE = Failure.
    @comm    
    @xref   
*/
BOOL OEMEthSendFrame(PUCHAR pData, DWORD dwLength)
{
    BYTE Retries = 0;
    while (Retries++ < 4)
    {

        if (!pfnEDbgSendFrame(pData, dwLength))
            return(TRUE);

        EdbgOutputDebugString("INFO: OEMEthSendFrame: retrying send (%u)\r\n", Retries);
    }

    return(FALSE);
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL InitUSBEthDevice(PBOOT_CFG pBootCfg, OAL_KITL_ARGS *pKITLArgs)
{
    // Set address
    //EbootDeviceAddress = (UINT32)OALPAtoVA(BULVERDE_BASE_REG_PA_UDC, FALSE);  // Base Address for USB Client

    memcpy((UCHAR *)pKITLArgs->mac, pBootCfg->CS8900MAC, 6);
    //pKITLArgs->mac[0] = pBootCfg->RNDISMac[0];
    //pKITLArgs->mac[1] = pBootCfg->RNDISMac[1];
    //pKITLArgs->mac[2] = pBootCfg->RNDISMac[2];
            
    // init USB registers
    if (HostMiniInit((PCHAR)AK_BASE_REG_PA_USB, 1, pKITLArgs->mac))
    {
        pfnEDbgInit           = RndisInit;
        pfnEDbgEnableInts     = RndisEnableInts;
        pfnEDbgDisableInts    = RndisDisableInts;    
        pfnEDbgGetFrame       = RndisEDbgGetFrame_stub;       
        pfnEDbgSendFrame      = RndisEDbgSendFrame;      
        pfnEDbgReadEEPROM     = NULL;     
        pfnEDbgWriteEEPROM    = NULL;    

        // TODO: These two functons are provided in \oak\drivers\ethdbg\rne_mdd but not in \oak\drivers\netcard\rndismini

        pfnEDbgGetPendingInts = RndisGetPendingInts;  // TODO: This is called in OEMEthISR - what to do
        pfnEDbgSetOptions     = RndisSetOptions;   // TODO: This function does nothing

        //pKITLArgs->flags |= OAL_KITL_FLAGS_POLL;

        // Save the device location information for later use.
        //
        pKITLArgs->devLoc.IfcType     = Internal;
        pKITLArgs->devLoc.BusNumber   = 0;
        pKITLArgs->devLoc.PhysicalLoc = (PVOID)AK_BASE_REG_PA_USB;    // not a real Ethernet card
        pKITLArgs->devLoc.LogicalLoc  = (DWORD)pKITLArgs->devLoc.PhysicalLoc;

        return TRUE;
    }
    else
    {
        EdbgOutputDebugString("ERROR: Failed to initialize Bulverde Rndis USB Ethernet controller.\n");
        return FALSE;
    }
}

extern OAL_ADDRESS_TABLE g_oalAddressTable[];
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
PVOID 
Phys2Virt(
    DWORD pfn
    ) 
{
    int i = 0;
    DWORD va;       // Virtual Base Address of section
    DWORD pa;       // Physical Base Address of section
    DWORD pau;      // Physical Address Upper Bound of section
    DWORD pfnmb;    // PFN rounded down to 1MB
    
    //PPTE g_pOEMAddressTable;
    //g_pOEMAddressTable = &g_oalAddressTable;
    
    //
    // The end of the table is marked by an entry with a ZERO size.
    //
    while(g_oalAddressTable[i].size) {
        va = g_oalAddressTable[i].CA & 0x1FF00000;
        pa = g_oalAddressTable[i].PA & 0xFFF00000;
        pau = pa + (g_oalAddressTable[i].size << 20) - 1;
        pfnmb = pfn & 0xfff00000;
        if ((pfnmb >= pa) && (pfnmb <= pau))
            return ((PVOID) ((pfn - pa) + va + 0x80000000));
        i++;
    }
    //DEBUGMSG(ZONE_PHYSMEM, (TEXT("Phys2Virt() : PFN (0x%08X) not found!\r\n"), pfn));
    return NULL;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
LPVOID
NKCreateStaticMapping(
    DWORD dwPhysBase,
    DWORD dwSize
    ) 
{
    DWORD dwStart, dwEnd;

    dwPhysBase <<= 8;   // ARM only supports 32-bit physical address.

    if (dwStart = (DWORD) Phys2Virt(dwPhysBase)) {
        
        dwEnd = (DWORD) Phys2Virt(dwPhysBase + dwSize - 1);
            
        if (dwStart + dwSize - 1 != dwEnd) {
            //
            // Start of the requested region was already mapped, but size is too big
            //
            //KSetLastError(pCurThread, ERROR_INVALID_PARAMETER);
            return NULL;
        }

        //
        // UNCACHED virtual access only.
        //
        return (LPVOID) (dwStart | 0x20000000);
    }
    return NULL;
}


BOOL EbSimuEthInit(BYTE *pbBaseAddress, DWORD dwMultiplier, USHORT MacAddr[3]);
UINT16 EbSimuEthGetFrame(PUCHAR pData, PUSHORT pwLength);
UINT16 EbSimuEthSendFrame(PUCHAR pData, DWORD dwLength);

BOOL InitEbSimuDevice(PBOOT_CFG pBootCfg)
{

	pfnEDbgInit 		  = EbSimuEthInit;
	pfnEDbgEnableInts	  = NULL;
	pfnEDbgDisableInts	  = NULL;	 
	pfnEDbgGetFrame 	  = EbSimuEthGetFrame; 	  
	pfnEDbgSendFrame	  = EbSimuEthSendFrame; 	 
	pfnEDbgReadEEPROM	  = NULL;	  
	pfnEDbgWriteEEPROM	  = NULL;

	pfnEDbgInit((BYTE *)pBootCfg, NULL, pBootCfg->CS8900MAC);

	return TRUE;
}



